﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;

namespace _5E.Utils.ReflectionHelper
{
    /// <summary>
    /// 程序说明：动态方法存取
    /// 创建作者：ahl
    /// 创建时间：2012-03-25
    /// </summary>
    public class DynamicMethod
    {
        #region 变量

        /// <summary>
        /// 执行委托
        /// </summary>
        Func<object, object[], object> m_execute;

        #endregion

        #region 构造函数

        public DynamicMethod(MethodInfo methodInfo)
        {
            m_execute = GetExecuteDelegate(methodInfo);
        }

        #endregion

        #region 方法

        /// <summary>
        /// 获取方法Invoke
        /// </summary>
        /// <returns></returns>
        public Func<object, object[], object> GetMethodInvoke()
        {
            return m_execute;
        }

        /// <summary>
        /// 获取相当于Invoke的方法
        /// </summary>
        /// <param name="methodInfo"></param>
        /// <returns></returns>
        Func<object, object[], object> GetExecuteDelegate(MethodInfo methodInfo)
        {
            // 创建对象、参数
            ParameterExpression instanceParameter =
                Expression.Parameter(typeof(object), "instance");
            ParameterExpression parametersParameter =
                Expression.Parameter(typeof(object[]), "parameters");

            // 创建参数列表
            IList<Expression> parameterExpressions = BuildParameterExpressions(methodInfo, parametersParameter);

            // 判断是否静态
            Expression instanceCast = methodInfo.IsStatic ? null :
                Expression.Convert(instanceParameter, methodInfo.ReflectedType);

            // 类调用
            MethodCallExpression methodCall = Expression.Call(
                instanceCast, methodInfo, parameterExpressions);

            // 返回值为空
            if (methodCall.Type == typeof(void))
            {
                Expression<Action<object, object[]>> lambda =
                    Expression.Lambda<Action<object, object[]>>(methodCall, instanceParameter, parametersParameter);

                Action<object, object[]> execute = lambda.Compile();
                return (instance, parameters) =>
                {
                    execute(instance, parameters);
                    return null;
                };
            }
            else
            {
                UnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object));
                Expression<Func<object, object[], object>> lambda =
                    Expression.Lambda<Func<object, object[], object>>(castMethodCall, instanceParameter, parametersParameter);

                return lambda.Compile();
            }
        }

        /// <summary>
        /// 创建参数列表
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        IList<Expression> BuildParameterExpressions(MethodInfo method, ParameterExpression parametersParameter)
        {
            IList<Expression> parameterExpressions = new List<Expression>();
            ParameterInfo[] paramInfos = method.GetParameters();
            for (int i = 0; i < paramInfos.Length; i++)
            {
                BinaryExpression valueObj = Expression.ArrayIndex(
                    parametersParameter, Expression.Constant(i));
                UnaryExpression valueCast = Expression.Convert(
                    valueObj, paramInfos[i].ParameterType);

                parameterExpressions.Add(valueCast);
            }
            return parameterExpressions;
        }

        #endregion
    }
}
